reserved = {'any' : 'ANY', 'all' : 'ALL'}

tokens = [
    'ID_TABLA', 'ID_COLUMNA', 'MAX', 'MIN', 'SUM', 'AVG',
    'LIT','COMILLAS','ON', 'IN',
    'NOTIN', 'UNION', 'INTERSECT',  
    'ORDERASC', 'ORDERDESC', 'COUNTD','COUNT','GROUP',
    'APAREN','CPAREN','ARECTO','CRECTO','OR','AND','JOIN','LOJ','ROJ','FOJ',
    'JOINON','IGUAL','MENOR','MENORIGUAL','MAYOR','MAYORIGUAL','PUNTO','DOSPUNTOS','COMA',
    'NUM','POR','MAS','MENOS','DIVIDIR',
    ] + list(reserved.values())

# Tokens

t_MAX       = r'@\>'
t_MIN       = r'@\<'
t_SUM       = r'@\+'
t_AVG       = r'@\-'
t_COMILLAS  = r'\"'
t_ON        = r'-\>'
t_IN        = r'\<-'
t_NOTIN     = r'\</-'
t_UNION     = r'\\/'
t_INTERSECT = r'/\\'
t_ORDERASC  = r'<:'
t_ORDERDESC = r'>:'
t_COUNTD    = r'\#\#'
t_COUNT     = r'\#'
t_GROUP     = r'@'
t_APAREN    = r'\('
t_CPAREN    = r'\)'
t_ARECTO    = r'\['
t_CRECTO    = r'\]'
t_OR        = r'\|\|'
t_AND       = r'&&'
t_JOIN      = r'><'
t_LOJ       = r'\|><'
t_ROJ       = r'><\|'
t_FOJ       = r'\|><\|'
t_JOINON    = r'\|'
t_IGUAL     = r'=='
t_MENOR     = r'<'
t_MENORIGUAL = r'<='
t_MAYOR     = r'>'
t_MAYORIGUAL = r'>='
t_PUNTO     = r'.'
t_DOSPUNTOS = r':'
t_COMA      = r','
t_POR       = r'\*'
t_MAS       = r'\+'
t_MENOS     = r'-'
t_DIVIDIR   = r'/'

t_ignore = " "

precedence = (
    ('left', 'COMA'),
    ('left', 'AND'),
    ('nonassoc', 'MENORIGUAL', 'IGUAL'),
    ('nonassoc', 'MENOR', 'IGUAL'),
    ('nonassoc', 'MAYORIGUAL', 'IGUAL'),
    ('nonassoc', 'MAYOR', 'IGUAL'),
    ('left', 'MAS','MENOS'),
    ('left', 'POR','DIVIDIR'),
    )

def t_NUM(t):
    r'-?\d+(\.\d+)?'
    try:
        t.value = float(t.value)
    except ValueError:
        print("Error converting string to float: %d", t.value)
        t.value = 0
    return t

def t_LIT(t):
    r'\"([^"]*(\")*)*\"'
    t.type = reserved.get(t.value,'LIT')
    return t

def t_ID_TABLA(t):
    r'[A-Z]+[A-Z_0-9]*[a-z]+[A-Za-z_0-9]*'
    t.type = reserved.get(t.value,'ID_TABLA')    # Check for reserved words
    return t

def t_ID_COLUMNA(t):
    r'[a-z]+[A-Za-z_0-9]*'
    t.type = reserved.get(t.value,'ID_COLUMNA')    # Check for reserved words
    return t

def t_error(t):
    print("Illegal character '%s'" % t.value[0])
    t.lexer.skip(1)

# Build the lexer
import ply.lex as lex
lex.lex()

from AST import *

#CONSULTAS
    
def p_consulta_tabla_proyecciones(t):
    'consulta : tabla ARECTO proyeccion CRECTO'
    t[0] = Consulta(t[1],t[3])

def p_consulta_tabla_restricciones(t):
    'consulta : tabla APAREN restricciones CPAREN'
    t[0] = Consulta(t[1],None,t[3]) 
    
def p_consulta_tabla_proy_res(t):
    'consulta : tabla APAREN restricciones CPAREN ARECTO proyeccion CRECTO'
    t[0] = Consulta(t[1],t[6],t[3])        

   
def p_consulta_tabla(t):
    'consulta : tabla'
    t[0] = Consulta(t[1])

# Consula -> TABLA PUNTO COUNT
def p_consulta_punto_count(t):
    'consulta : tabla PUNTO COUNT'
    una_proyeccion = Count()
    proyecciones = Proyecciones(una_proyeccion)
    t[0] = Consulta(t[1], proyecciones)
    
def p_consulta_punto_res_count(t):
    'consulta : tabla APAREN restricciones CPAREN PUNTO COUNT'
    una_proyeccion = Count()
    proyecciones = Proyecciones(una_proyeccion)
    t[0] = Consulta(t[1], proyecciones, t[3])

# Consulta -> Tabla PUNTO ID_COLUMNA    
def p_consulta_punto_idcolumna(t):
    'consulta : tabla PUNTO ID_COLUMNA'
    una_proyeccion = Proyeccion_simple(t[3])
    proyecciones = Proyecciones(una_proyeccion)
    t[0] = Consulta(t[1], proyecciones)

# Consulta -> Consulta UNION Consulta
def p_consulta_union_consulta(t):
    'consulta : consulta UNION consulta'    
    t[0] = Union(t[1],t[3])
# Consulta -> Consulta INTERSECT Consulta
def p_consulta_intersect_consulta(t):
    'consulta : consulta INTERSECT consulta'
    t[0] = Intersect(t[1],t[3])
# Consulta -> Consulta MENOS Consulta
def p_consulta_minus_consulta(t):
    'consulta : consulta MENOS consulta'
    t[0] = Minus(t[1],t[3])
# Consulta -> Consulta MAS Consulta
def p_consulta_add_consulta(t):
    'consulta : consulta MAS consulta'
    t[0] = Add(t[1],t[3])
    
#RESTRICCIONES

#Restricciones : Restriccion
def p_restricciones(t):
    'restricciones : restriccion COMA restricciones'
    t[0] = Restricciones(t[1],t[3])

#Restricciones : Restriccion
def p_restriccion(t):
    'restricciones : restriccion'
    t[0] = Restricciones(t[1])

def p_res_and(t):
    'restriccion : restriccion AND restriccion'
    t[0] = And(t[1],t[3])
    
def p_res_or(t):
    'restriccion : restriccion OR restriccion'
    t[0] = Or(t[1],t[3])
    
def p_res_in(t):
    'restriccion : ID_COLUMNA IN consulta'
    t[0] = RestriccionIn(t[1],t[3],True)

def p_res_not_in(t):
    'restriccion : ID_COLUMNA NOTIN consulta'
    t[0] = RestriccionIn(t[1],t[3],False)
    
def p_res_eq_all(t):
    'restriccion : ID_COLUMNA IGUAL ALL consulta'
    t[0] = RestriccionEqual(t[1],t[4],True)

def p_res_eq_any(t):
    'restriccion : ID_COLUMNA MENOR ANY consulta'
    t[0] = RestriccionEqual(t[1],t[4],False)

def p_res_exp(t):
    'restriccion : aexp'
    t[0] = RestriccionExp(t[1])
    
# Selecciones

# Seleccion ->  Consulta COMA Consulta
def p_seleccion_consulta_coma_consulta(t):
    'seleccion : consulta COMA consulta'
    t[0] = Cartesiano(t[1],t[3])
    
def p_seleccion_join(t):
    'seleccion : consulta JOIN seljoin'
    t[0] = Join(t[1],t[3],'join')

def p_seleccion_loj(t):
    'seleccion : consulta LOJ seljoin'
    t[0] = Join(t[1],t[3],'left')

def p_seleccion_roj(t):
    'seleccion : consulta ROJ seljoin'
    t[0] = Join(t[1],t[3],'right')

def p_seleccion_foj(t):
    'seleccion : consulta FOJ seljoin'
    t[0] = Join(t[1],t[3],'full')

def p_seleccion_join2(t):
    'seljoin : consulta JOIN seljoin'
    t[0] = Join(t[1],t[3],'join')

def p_seleccion_join2_loj(t):
    'seljoin : consulta LOJ seljoin'
    t[0] = Join(t[1],t[3],'left')

def p_seleccion_join2_roj(t):
    'seljoin : consulta ROJ seljoin'
    t[0] = Join(t[1],t[3],'right')
    
def p_seleccion_join2_foj(t):
    'seljoin : consulta FOJ seljoin'
    t[0] = Join(t[1],t[3],'full')
    
def p_seleccion_join3(t):
    'seljoin : consulta'
    t[0] = Consulta(t[1])
    
#TABLA
def p_tabla(t):
    'tabla : ID_TABLA'
    t[0] = Tabla(ID(t[1]))
    
def p_tabla_seleccion(t):
    'tabla : APAREN seleccion CPAREN'
    t[0] = t[2]
    
#PROYECCIONESs
def p_proyecciones(t):
    'proyeccion : proyeccion COMA proyeccion'
    t[0] = Proyecciones(t[1],t[3])

def p_proy_sum(t):
    'proyeccion : SUM APAREN ID_COLUMNA CPAREN'
    t[0] = ProySum(t[3])

def p_proy_avg(t):
    'proyeccion : AVG APAREN ID_COLUMNA CPAREN'
    t[0] = ProyAvg(t[3])
    
def p_proy_min(t):
    'proyeccion : MIN APAREN ID_COLUMNA CPAREN'
    t[0] = ProyMin(t[3])
    
def p_proy_max(t):
    'proyeccion : MAX APAREN ID_COLUMNA CPAREN'
    t[0] = ProyMax(t[3])

def p_proy_count(t):
    'proyeccion : COUNT APAREN ID_COLUMNA CPAREN'
    t[0] = ProyCount(t[3])

def p_proy_countd(t):
    'proyeccion : COUNTD APAREN ID_COLUMNA CPAREN'
    t[0] = ProyCount(t[3], True)
    
def p_proyeccion_con_id(t):
    'proyeccion : ID_COLUMNA DOSPUNTOS aexp'
    t[0] = ProyeccionConNombre(t[1], t[3])   
    
def p_proyeccion(t):
    'proyeccion : aexp'
    t[0] = ProyeccionColumna(t[1])

def p_proy_order_asc(t):
    'proyeccion : ORDERASC ID_COLUMNA'
    t[0] = OrderBy(t[2], True)
    
def p_proy_order_desc(t):
    'proyeccion : ORDERDESC ID_COLUMNA'
    t[0] = OrderBy(t[2], False)
    
def p_suma(t):
    'aexp : aexp MAS aexp'
    t[0] = Suma(t[1],t[3])

def p_resta(t):
    'aexp : aexp MENOS aexp'
    t[0] = Resta(t[1],t[3])

def p_por(t):
    'aexp : aexp POR aexp'
    t[0] = Por(t[1],t[3])

def p_dividir(t):
    'aexp : aexp DIVIDIR aexp'
    t[0] = Dividir(t[1],t[3])

def p_exp_igual(t):
    'aexp : aexp IGUAL aexp'
    t[0] = Igual(t[1],t[3])
    
def p_exp_menor_igual(t):
    'aexp : aexp MENORIGUAL aexp'
    t[0] = MenorIgual(t[1],t[3])
    
def p_exp_mayor_igual(t):
    'aexp : aexp MAYORIGUAL aexp'
    t[0] = MayorIgual(t[1],t[3])

def p_exp_mayor(t):
    'aexp : aexp MAYOR aexp'
    t[0] = Mayor(t[1],t[3])

def p_exp_menor(t):
    'aexp : aexp MENOR aexp'
    t[0] = Menor(t[1],t[3])
    
def p_constante(t):
    'aexp : NUM'
    t[0] = Constante(t[1])
    
def p_columna(t):
    'aexp : variable'
    t[0] = t[1]

def p_lit(t):
    'aexp : LIT'
    t[0] = Constante(t[1])

def p_nom_columna(t):
    'variable : ID_COLUMNA'
    t[0] = Columna(t[1])
        
def p_foreign_key(t):
    'variable : ID_COLUMNA ON variable'
    t[0] = ForeignKey(t[1], t[3])
    
import ply.yacc as yacc
yacc.yacc()
    
def main():
    global evalData
    global validData
    global bdConn
    print '\nConsultas start...\n'
    while 1:
        try:
            consulta = ""
            s = raw_input('consulta > ')   # Use raw_input on Python 2
            evalData = None
            validData.reset()
            yacc.parse(s).validar()
            if validData.esValido():
                consulta = yacc.parse(s).compilar()
             #   print consulta
            else:
                for e in validData.errores:
                    print e
            print ''
            resConsulta = bdConn.consultarBD(consulta)
            for i in resConsulta:
                print i
        except EOFError:
            pass
        #print yacc.parse(s)
    print 'Consulta end.\n'

if __name__ == '__main__':
    main()